#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
修复certifi证书问题
"""

import os
import subprocess
import sys
import shutil
from datetime import datetime

def fix_certifi():
    """修复certifi问题"""
    print("修复certifi问题...")
    
    # 卸载相关包
    packages = ['certifi', 'requests', 'urllib3']
    for package in packages:
        print(f"卸载 {package}...")
        subprocess.run([sys.executable, "-m", "pip", "uninstall", package, "-y"])
    
    # 安装兼容版本
    print("安装兼容版本...")
    subprocess.run([sys.executable, "-m", "pip", "install", "certifi==2021.10.8"])
    subprocess.run([sys.executable, "-m", "pip", "install", "requests==2.28.2"])
    subprocess.run([sys.executable, "-m", "pip", "install", "urllib3==1.26.15"])
    
    print("✓ certifi已修复")

def create_certifi_spec():
    """创建包含certifi证书的spec文件"""
    print("创建包含证书文件的spec文件...")
    
    # 获取certifi证书路径
    try:
        import certifi
        certifi_path = certifi.where()
        print(f"找到certifi证书文件: {certifi_path}")
        # 修复路径中的反斜杠问题
        certifi_path = certifi_path.replace('\\', '/')
        print(f"修复后的路径: {certifi_path}")
    except ImportError:
        print("警告: 无法导入certifi")
        return None
    
    spec_content = f'''# -*- mode: python ; coding: utf-8 -*-

block_cipher = None

# 图标文件
icon_file = 'icon.ico' if os.path.exists('icon.ico') else None

# 数据文件
datas = []
if os.path.exists('icon.ico'):
    datas.append(('icon.ico', '.'))

# 添加certifi证书文件
datas.append(('{certifi_path}', 'certifi'))

# 添加AI插件程序
if os.path.exists('ui_plugin_pyqt5.py'):
    datas.append(('ui_plugin_pyqt5.py', '.'))

# 隐藏导入
hiddenimports = [
    'PyQt5.QtCore',
    'PyQt5.QtGui', 
    'PyQt5.QtWidgets',
    'PyQt5.sip',
    'requests',
    'urllib3',
    'certifi',
    'certifi.core',
    'certifi.cacert',
    'paramiko',
    'paramiko.transport',
    'paramiko.client',
    'paramiko.sftp_client',
    'paramiko.ssh_exception',
    'paramiko.dsskey',
    'paramiko.pkey',
    'cryptography',
    'cryptography.hazmat',
    'cryptography.hazmat.primitives',
    'cryptography.hazmat.primitives.ciphers',
    'cryptography.hazmat.primitives.ciphers.base',
    'cryptography.hazmat.primitives.ciphers.modes',
    'cryptography.hazmat.primitives.hashes',
    'cryptography.hazmat.primitives.kdf',
    'cryptography.hazmat.primitives.asymmetric',
    'cryptography.hazmat.primitives.serialization',
    'cryptography.hazmat.backends',
    'cryptography.hazmat.backends.openssl',
    'cryptography.exceptions',
    'cryptography.utils',
    'cryptography.hazmat.bindings',
    'cryptography.hazmat.bindings.openssl',
    'cryptography.hazmat.bindings._openssl',
    'bcrypt',
    'pynacl',
    'cffi',
    'cffi.api',
    'cffi.cparser',
    'cffi.ffiplatform',
    'cffi.lock',
    'cffi.verifier',
    'pycparser',
    'pycparser.c_ast',
    'pycparser.c_parser',
    'pycparser.lextab',
    'pycparser.yacctab',
    'sqlite3',
    'winreg',
    'json',
    'datetime',
    'os',
    'sys',
    'login',
    'cloud_sync',
    'user_manager',
    'webdav_sync'
]

# 排除可能导致问题的模块
excludes = [
    'tkinter',
    'matplotlib',
    'numpy',
    'pandas',
    'scipy',
    'PIL',
    'cv2',
    'jupyter',
    'IPython',
    'notebook'
]

a = Analysis(
    ['main.py'],
    pathex=[],
    binaries=[],
    datas=datas,
    hiddenimports=hiddenimports,
    hookspath=[],
    hooksconfig={{}},
    runtime_hooks=[],
    excludes=excludes,
    win_no_prefer_redirects=False,
    win_private_assemblies=False,
    cipher=block_cipher,
    noarchive=False,
)

pyz = PYZ(a.pure, a.zipped_data, cipher=block_cipher)

exe = EXE(
    pyz,
    a.scripts,
    a.binaries,
    a.zipfiles,
    a.datas,
    [],
    name='待办事项管理',
    debug=False,
    bootloader_ignore_signals=False,
    strip=False,
    upx=True,
    upx_exclude=[],
    runtime_tmpdir=None,
    console=False,
    disable_windowed_traceback=False,
    argv_emulation=False,
    target_arch=None,
    codesign_identity=None,
    entitlements_file=None,
    icon=icon_file,
)
'''
    
    with open('certifi_fixed.spec', 'w', encoding='utf-8') as f:
        f.write(spec_content)
    
    return 'certifi_fixed.spec'

def clean_old_files():
    """清理旧文件"""
    print("清理旧文件...")
    dirs_to_clean = ['build', 'dist', '__pycache__']
    for dir_name in dirs_to_clean:
        if os.path.exists(dir_name):
            shutil.rmtree(dir_name)
            print(f"已删除 {dir_name}")

def build_executable():
    """构建可执行文件"""
    print("开始打包...")
    
    # 创建包含证书的spec文件
    spec_file = create_certifi_spec()
    if not spec_file:
        print("✗ 无法创建spec文件")
        return False
    
    # 构建主程序
    print("构建主程序...")
    cmd_main = [
        sys.executable, "-m", "PyInstaller",
        spec_file,
        "--clean"
    ]
    
    print(f"执行主程序打包命令: {' '.join(cmd_main)}")
    
    try:
        result = subprocess.run(cmd_main, capture_output=True, text=True, timeout=600)
        
        if result.returncode != 0:
            print("✗ 主程序打包失败！")
            print("错误信息:")
            print(result.stderr)
            return False
        else:
            print("✓ 主程序打包成功！")
    except subprocess.TimeoutExpired:
        print("✗ 主程序打包超时")
        return False
    except Exception as e:
        print(f"✗ 主程序打包错误: {e}")
        return False
    
    # 构建AI插件程序
    print("构建AI插件程序...")
    if os.path.exists("ui_plugin_pyqt5.py"):
        cmd_plugin = [
            sys.executable, "-m", "PyInstaller",
            "--onefile",
            "--windowed",
            "--icon=icon.ico",
            "--name=AI插件",
            "ui_plugin_pyqt5.py"
        ]
        
        print(f"执行AI插件打包命令: {' '.join(cmd_plugin)}")
        
        try:
            result = subprocess.run(cmd_plugin, capture_output=True, text=True, timeout=300)
            
            if result.returncode == 0:
                print("✓ AI插件打包成功！")
            else:
                print("✗ AI插件打包失败！")
                print("错误信息:")
                print(result.stderr)
                # 插件打包失败不影响主程序，继续执行
        except subprocess.TimeoutExpired:
            print("✗ AI插件打包超时")
        except Exception as e:
            print(f"✗ AI插件打包错误: {e}")
    else:
        print("- AI插件文件不存在，跳过打包")
    
    return True

def copy_required_files():
    """复制必要文件"""
    print("复制必要文件...")
    
    dist_dir = "dist"
    if not os.path.exists(dist_dir):
        print("✗ dist目录不存在")
        return
    
    files_to_copy = [
        ("default_todo_data.db", "数据库文件"),
        ("lock.json", "锁定配置文件"),
        ("icon.ico", "图标文件"),
        ("ui_plugin_pyqt5.py", "AI插件程序")
    ]
    
    for file_name, desc in files_to_copy:
        if os.path.exists(file_name):
            dest_path = os.path.join(dist_dir, file_name)
            shutil.copy2(file_name, dest_path)
            print(f"✓ 已复制{desc}: {file_name}")
        else:
            print(f"- {desc}不存在: {file_name}")

def cleanup():
    """清理临时文件"""
    print("清理临时文件...")
    if os.path.exists('certifi_fixed.spec'):
        os.remove('certifi_fixed.spec')
        print("已删除临时spec文件")

def main():
    print("=" * 60)
    print("certifi证书问题修复工具")
    print("专门解决WebDAV连接中的证书问题")
    print(f"开始时间: {datetime.now()}")
    print("=" * 60)
    
    # 检查main.py是否存在
    if not os.path.exists("main.py"):
        print("✗ 错误: 找不到main.py文件")
        return
    
    # 修复certifi
    fix_certifi()
    
    # 清理旧文件
    clean_old_files()
    
    # 构建可执行文件
    if build_executable():
        # 复制必要文件
        copy_required_files()
        
        # 清理临时文件
        cleanup()
        
        print("\n" + "=" * 60)
        print("✓ 打包完成！")
        print(f"主程序可执行文件位置: dist/待办事项管理.exe")
        print(f"AI插件可执行文件位置: dist/AI插件.exe")
        print("此版本包含了certifi证书文件，应该解决WebDAV连接问题")
        print("=" * 60)
    else:
        print("\n" + "=" * 60)
        print("✗ 打包失败，请检查错误信息")
        print("=" * 60)

if __name__ == "__main__":
    main() 